﻿using System;
using System.Collections.Generic;
using System.Text;
using OpenTK;

using OpenTK;
using OpenTK.Graphics.OpenGL;


namespace Xeno.Core
{
    public class XenoFilter 
    {
        public XenoRenderTarget Target = null;
        public XenoTexture2D FrameBuffer = null;
        public XenoTextureDepth DepthBuffer = null;
        public bool NeedsFrame { get; set; }
        public XenoMaterial FrameMat { get; set; }
        public XenoMaterial TmpMat { get; set; }
        public XenoTexture2D Output { get; set; }
        public XenoTextureDepth OutputDepth { get; set; }
        public XenoGraph ActualGraph { get; set; }
        public XenoMaterial TransferMat { get; set; }
        public XenoMaterial BlurMat { get; set; }
        public XenoTexture2D WhiteMap { get; set; }
        public XenoFilter(int res)
        {
            
            Target = new XenoRenderTarget();
            FrameBuffer = new XenoTexture2D(res, res);
            DepthBuffer = new XenoTextureDepth(res, res);
            TmpMat = new XenoMaterial("TmpMat",XenoMaterial.MaterialFlags.X2D);
            Output = new XenoTexture2D((int)XenoCore.DisplayWidth, (int)XenoCore.DisplayHeight);
            OutputDepth = new XenoTextureDepth((int)XenoCore.DisplayWidth, (int)XenoCore.DisplayHeight);
            NeedsFrame = true;
            TransferMat = new XenoMaterial("TransferMat", XenoMaterial.MaterialFlags.X2D);
            TransferMat.Effect = null;
            BlurMat = new XenoMaterial("BlurMat", XenoMaterial.MaterialFlags.X2D);
            BlurMat.Effect = new XenoEffect("", "Content/Shader/XenoMaterial_PixelBlur.fragment");
            
        }

        public void PerformUpdate(XenoGraph graph)
        {
        }
        public void CheckMaps()
        {
            if (WhiteMap == null)
            {
                WhiteMap = new XenoTexture2D(128, 128);
                Target.Bind();

                Target.AttachTexture(WhiteMap);
                GL.PushAttrib(AttribMask.AllAttribBits);
                GL.ClearColor(System.Drawing.Color.White);
                GL.Clear(ClearBufferMask.ColorBufferBit);
                GL.PopAttrib();
                Target.Unbind();
            }
        }
        public void PerformRender(XenoGraph graph,XenoTexture2D prev)
        {
            CheckMaps();
            FrameBuffer = prev;
            ActualGraph = graph;
            Output = DoRender();
            

        }
        
        public virtual XenoTexture2D DoRender()
        {
            return null;
        }
        public float[] blurKernel = new float[9];
        public float[] offSets = new float[18];

        public Vector2 vec2(double x, double y)
        {
            return new Vector2((float)x, (float)y);
        }
        public void BlurBuffer(XenoTexture2D toBlur, XenoTexture2D blurMap,XenoTexture2D to)
        {

            float step_w = 1.0f / XenoCore.DisplayWidth;
            float step_h = 1.0f / XenoCore.DisplayHeight;
            step_w *= 12;
            step_h *= 12;


            blurKernel = new float[9]{ 1.0f/16.0f, 2.0f/16.0f, 1.0f/16.0f,
				2.0f/16.0f, 4.0f/16.0f, 2.0f/16.0f,
				1.0f/16.0f, 2.0f/16.0f, 1.0f/16.0f };

            offSets = new float[18]{ -step_w, -step_h, 0.0f,step_h,step_w, -step_h, 
				-step_w, 0.0f, 0.0f, 0.0f,step_w, 0.0f, 
				-step_w, step_h, 0.0f, step_h,step_w, step_h };

      

            BufferToBuffer(toBlur, to, BlurMat);
            Target.Bind();
            Target.AttachTexture(to);

            BlurMat.DiffuseMap = toBlur;
            BlurMat.NormalMap = blurMap;

            BlurMat.Bind();

            BlurMat.Effect.SetFloats("kernel", blurKernel);
            BlurMat.Effect.SetFloats("offset", offSets);

            DrawQuad(0, 0, to.Width, to.Height);

            BlurMat.Unbind();

            Target.Unbind();

        }
        public void BufferToBuffer(XenoTexture2D from, XenoTexture2D to,XenoMaterial material)
        {

            Target.Bind();
            Target.AttachTexture(to);

            material.DiffuseMap = from;

            DrawMat(0, 0, to.Width, to.Height, material);

            Target.Unbind();

        }
        public virtual void GraphToBuffer(XenoTexture2D buffer, XenoTextureDepth depth,XenoGraph graph, XenoMaterial material)
        {
            
            XenoCore.MaterialOverride = material;
            Target.Bind();
            Target.AttachTexture(buffer);
            Target.AttachDepth(depth);

            graph.RootNode.PerformRender();

            Target.Unbind();
            XenoCore.MaterialOverride = null;

        }
        public virtual void DrawQuad(float x,float y,float w,float h)
        {
            XuiWidget.Begin2D();

            GL.Color4(System.Drawing.Color.White);
            GL.Disable(EnableCap.Blend);

            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0, 1);
            GL.Vertex2(x, y);
            GL.TexCoord2(1, 1);
            GL.Vertex2(x + w, y);
            GL.TexCoord2(1, 0);
            GL.Vertex2(x + w, y + h);
            GL.TexCoord2(0, 0);
            GL.Vertex2(x, y + h);

            GL.End();

            XuiWidget.End2D();
        }
        public virtual void DrawMat(float x, float y, float w, float h, XenoMaterial mat)
        {
            mat.Bind();

            XuiWidget.Begin2D();

            GL.Color4(System.Drawing.Color.White);
            GL.Disable(EnableCap.Blend);

            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0, 1);
            GL.Vertex2(x, y);
            GL.TexCoord2(1, 1);
            GL.Vertex2(x + w, y);
            GL.TexCoord2(1, 0);
            GL.Vertex2(x + w, y + h);
            GL.TexCoord2(0, 0);
            GL.Vertex2(x, y + h);

            GL.End();

            XuiWidget.End2D();
            mat.Unbind();
        }
    }

}
